// ComPort.cpp : 实现文件
//

#include "stdafx.h"
#include "ComPort.h"


namespace LsComm{

// CComPort

CComPort::CComPort()
{
	this->m_pfnOnReceiveData = NULL;
    this->m_pfnOnComBreak =NULL;
	this->m_pPort = NULL;
	this->m_pReadThread = NULL;
	::ZeroMemory(&this->m_WriteOverlapped,sizeof(this->m_WriteOverlapped));
    this->m_hWriteEvent = NULL;
}

CComPort::~CComPort()
{
	if(this->m_pPort)
	{
		if(this->m_pPort->IsOpen())
		{
		   this->Close(); 
		}
	}

	if(this->m_pPort)
	{
	   delete this->m_pPort; 
	   this->m_pPort = NULL;
	}
}


// CComPort 成员函数

void CComPort::Open(int nPort,ReceiveMode mode, DWORD dwBaud, Parity parity, BYTE DataBits, 
            StopBits stopbits,FlowControl fc)
{   
	//1.新建串口
	this->m_pPort = new CSerialPort();

	//2.判断收发模式
	if(mode==ReceiveMode::ManualReceiveByQuery)
	{
	   this->m_IsOverlapped  = false;
	}
	else
	{
	   this->m_IsOverlapped  = true;
	}
    this->m_RecvMode = mode; 
    
	//3.转换参数,打开串口
	int index;
	index=parity-CComPort::EvenParity;
	CSerialPort::Parity spParity=(CSerialPort::Parity)(CSerialPort::EvenParity+index);
	index=stopbits-CComPort::OneStopBit;
	CSerialPort::StopBits spStopbits=(CSerialPort::StopBits)(CSerialPort::OneStopBit+index);
    index=fc-CComPort::NoFlowControl;
	CSerialPort::FlowControl spFC=(CSerialPort::FlowControl)(CSerialPort::NoFlowControl+index) ;
         
	this->m_pPort->Open(nPort,dwBaud,spParity,DataBits,spStopbits,spFC,m_IsOverlapped); 
    this->m_pPort->Setup(4096, 4096);      
	this->m_pPort->Purge(PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
	//it is important!!
	COMMTIMEOUTS timeouts;
	this->m_pPort->GetTimeouts(timeouts);
    timeouts.ReadIntervalTimeout=100;
	this->m_pPort->SetTimeouts(timeouts);

	this->m_CurPortNum = nPort;
  	//创建关闭事件
	this->m_hCloseEvent = CreateEvent(NULL,true,false,NULL);
	ASSERT(this->m_hCloseEvent); 
	//4.创建线程类
	this->m_pReadThread = new CReadComThread();
	this->m_pReadThread->BandSerialPort(this); 
	this->m_pReadThread->Create();
	this->m_pReadThread->Resume(); 

	if(this->IsOverlapped())
	{
	   this->m_hWriteEvent = ::CreateEvent(NULL,false,false,NULL);
	}
}

void CComPort::Close()
{
	//1.串口
	if(this->m_pPort==NULL)
		return;
	if(!this->m_pPort->IsOpen())
		return;
    //2.事件
	::SetEvent(this->m_hCloseEvent);//通知关闭系统
    Sleep(50);
	//3.结束读线程
	try
	{
      this->m_pReadThread->Terminate();   
      delete this->m_pReadThread;
      this->m_pReadThread = NULL;
	}
	catch(char e[150])
	{
		::AfxMessageBox(e); 
	}
   
   //4.结束关闭线程
   ::CloseHandle(this->m_hCloseEvent); 
   this->m_pPort->Close();
   
   //5.结束写事件
   if(this->m_hWriteEvent)
   {
	   ::CloseHandle(this->m_hWriteEvent);
	   this->m_hWriteEvent = NULL;
   }
   //6.释放串口对象
	if(this->m_pPort)
	{
		delete this->m_pPort;
	    this->m_pPort = NULL;
	}
}

void CComPort::ReceiveData(void* pBuf,DWORD InBufferCount)
{
   if(this->m_pfnOnReceiveData)
   this->m_pfnOnReceiveData(this->m_pSender,pBuf,InBufferCount); 
}

void CComPort::SetReceiveFunc(FOnReceiveData pfnOnReceiveData,LPVOID pSender)
{
   this->m_pfnOnReceiveData = pfnOnReceiveData;
   this->m_pSender = pSender;
}

void CComPort::ComBreak(DWORD dwMask)
{
   if(this->m_pfnOnComBreak)
   {
	   COMSTAT stat;
	   this->m_pPort->GetStatus(stat); 
       this->m_pfnOnComBreak(this->m_pPort,dwMask,stat);
   }
}

void CComPort::SetBreakHandleFunc(FOnComBreak pfnOnComBreak)
{
   this->m_pfnOnComBreak = pfnOnComBreak;
}



CComPort::ReceiveMode CComPort::GetReceiveMode()
{
	return this->m_RecvMode;
}

DWORD CComPort::GetInBufferCount()
{
   	if(this->IsOverlapped())
	{
		::AfxMessageBox("this methord is only used for ManualQueryMode!");
		return 0;
	}
	COMSTAT stat;
   ::ZeroMemory(&stat,sizeof(stat));
   this->m_pPort->GetStatus(stat);
   return stat.cbInQue; 
}


DWORD CComPort::GetInput(void* pBuf,DWORD Count,DWORD dwMilliseconds)
{   
	//不能在自动模式下getinput
	if(this->GetReceiveMode()==CComPort::AutoReceiveByBreak||
		this->GetReceiveMode()==CComPort::AutoReceiveBySignal)
	{
		::AfxMessageBox("Can't use GetInput methord in this mode!");
		return 0;
	}

	if(this->IsOverlapped())
	{
    	ASSERT(this->m_pReadThread); 
		DWORD dwBytes = 0;

		dwBytes = this->m_pReadThread->ReadInput(pBuf,Count,dwMilliseconds);  
		this->m_pPort->TerminateOutstandingReads(); 
	     
		return dwBytes;
	}
	else
	   return this->m_pPort->Read(pBuf,Count);  
}

DWORD CComPort::Output(void* pBuf,DWORD Count)
{   
    DWORD dwWriteBytes=0;
	if(this->IsOverlapped())//异步模式
	{
	   this->m_pPort->Write(pBuf,Count,this->m_WriteOverlapped);
	   if(WaitForSingleObject(this->m_WriteOverlapped.hEvent,INFINITE)==WAIT_OBJECT_0)
		{
		    this->m_pPort->GetOverlappedResult(this->m_WriteOverlapped,dwWriteBytes,false);
		}
	}
	else
	   dwWriteBytes= this->m_pPort->Write(pBuf,Count);  

	return dwWriteBytes;
}

 CSerialPort* CComPort::GetSerialPort() 
{ 
	ASSERT(m_pPort);
	return m_pPort;
}
HANDLE CComPort::GetCloseHandle()
{ 
	ASSERT(this->m_hCloseEvent);
	return this->m_hCloseEvent;
}

//CReadComThread

CReadComThread::CReadComThread()
{
	this->m_hThread = NULL;
	this->m_pPort = NULL;
	this->IsClose =false;
	::ZeroMemory(&this->m_BreakOverlapped,sizeof(this->m_BreakOverlapped));
	::ZeroMemory(&this->m_ReadOverlapped,sizeof(this->m_ReadOverlapped));
	
	memset(this->m_InputBuffer,0,2048); 
}

CReadComThread::~CReadComThread()
{
	this->m_hThread = NULL;
}


// CReadComThread 成员函数
bool CReadComThread::SetReadEvent(OVERLAPPED& overlapped)
{
 BeginSet:
	if(this->m_pPort->GetSerialPort()->Read(this->m_InputBuffer,2048,overlapped,&this->m_InBufferCount))
	{
	   if(!this->HandleData())
		   return  false;
	   ::ResetEvent(this->m_ReadOverlapped.hEvent);  
	   goto BeginSet;
	}
    DWORD error=::GetLastError();
	if(error==ERROR_IO_PENDING)
	{ return true; }
	else
	{ return false; }

}


bool CReadComThread::HandleData() //处理读取数据
{
   if(this->m_InBufferCount>0)
   {
      this->m_pBuffer = new byte[this->m_InBufferCount];
	  for(int i=0;i<(int)this->m_InBufferCount;i++)
	  {
	      this->m_pBuffer[i] = this->m_InputBuffer[i];  
	  }
      //this->m_pSerialPort->  
	  this->m_pPort->ReceiveData(this->m_pBuffer,this->m_InBufferCount);   
	  delete[] this->m_pBuffer; 
   }
   return true;
}


bool CReadComThread::HandleReadEvent(OVERLAPPED& overlapped)
{
	if(this->m_pPort->GetSerialPort()->GetOverlappedResult(overlapped,this->m_InBufferCount,false))
	{
	   return this->HandleData();
	}

	DWORD dwError = ::GetLastError();
	if(dwError==ERROR_INVALID_HANDLE)
		return false;
	else
		return true;
}

bool CReadComThread::SetBreakEvent(DWORD& dwMask )
{
SetBegin:
   if(this->m_pPort->GetSerialPort()->WaitEvent(dwMask,this->m_BreakOverlapped))
   {
      if(!this->HandleBreakEvent(dwMask))
		  return false;
	  goto SetBegin;
   }

    DWORD error=::GetLastError();
	if(error==ERROR_IO_PENDING)
	{ return true; }
	else
	{ return false; }
	//::AfxBeginThread(
}

bool CReadComThread::HandleBreakEvent(DWORD dwMask)
{
   DWORD dwReadBytes;
   bool successed=
      this->m_pPort->GetSerialPort()->GetOverlappedResult(this->m_BreakOverlapped,dwReadBytes,false);
   if(successed)
   {
	   this->m_pPort->ComBreak(dwMask); //调用处理过程
	   return true;
   }
   return false;
}

void CReadComThread::Execute()
{

	if(this->m_pPort->GetReceiveMode()==CComPort::ManualReceiveByQuery)
	{
	   this->ExecuteByManualQueryRecvMode(); 
	}
	else if(this->m_pPort->GetReceiveMode()==CComPort::ManualReceiveByConst)
	{
       this->ExecuteByManualConstRecvMode(); 	
	}
	else if(this->m_pPort->GetReceiveMode()==CComPort::AutoReceiveBySignal)
	{
	   this->ExecuteByAutoSignalRecvMode(); 
	}
	else//中断模式
	{
       this->ExecuteByAutoBreakRecvMode(); 
	}

}
void CReadComThread::ExecuteByAutoSignalRecvMode()
{
	DWORD dwMask=0;
	HANDLE WaitHandles[3]; //监听事件数组
	DWORD dwSignaledHandle;

	WaitHandles[0] = this->m_pPort->GetCloseHandle();
	WaitHandles[1] = this->m_ReadOverlapped.hEvent;
	WaitHandles[2] = this->m_BreakOverlapped.hEvent;

	this->m_pPort->GetSerialPort()->SetMask(EV_ERR | EV_RLSD | EV_RING ); 

	if(!SetBreakEvent(dwMask))
		goto EndThread;
	//设置读事件
	if(!SetReadEvent(this->m_ReadOverlapped))
		goto EndThread;

    //设置comEvent
	for(;;)
	{
	   dwSignaledHandle=::WaitForMultipleObjects(3,WaitHandles,false,INFINITE);
       switch(dwSignaledHandle)
	   {
	      case WAIT_OBJECT_0:
              goto EndThread; 
			  break;

	      case WAIT_OBJECT_0+1:
              if(!this->HandleReadEvent(this->m_ReadOverlapped))
			    goto EndThread;
   			  if(!this->SetReadEvent(this->m_ReadOverlapped))
        		  goto EndThread;
			  break;

	      case WAIT_OBJECT_0+2:
              if(!this->HandleBreakEvent(dwMask))
    				goto EndThread;
 
			  if(!this->SetBreakEvent(dwMask))
	        		  goto EndThread;
			  break;

		  default:
			  //goto EndThread;
			  break;
	   }
	   
  
	}

    EndThread:
	  	this->m_pPort->GetSerialPort()->Purge(PURGE_RXABORT | PURGE_RXCLEAR);  
	    ::CloseHandle(this->m_ReadOverlapped.hEvent);
	    ::CloseHandle(this->m_BreakOverlapped.hEvent);  
        return ;   

}

void CReadComThread::ExecuteByManualQueryRecvMode()
{
	DWORD dwMask=0;
	HANDLE WaitHandles[2]; //监听事件数组
	DWORD dwSignaledHandle;

	WaitHandles[0] = this->m_pPort->GetCloseHandle();
	
 	this->m_pPort->GetSerialPort()->SetMask(EV_ERR | EV_RLSD | EV_RING ); 
    this->m_pPort->GetSerialPort()->SetBreak(); 
 	for(;;)
	{
	   dwSignaledHandle=::WaitForMultipleObjects(1,WaitHandles,false,INFINITE);
       switch(dwSignaledHandle)
	   {
	      case WAIT_OBJECT_0:
              goto EndThread; 
			  break;

		  default:
			  //goto EndThread;
			  break;
	   }
 	   this->m_pPort->GetSerialPort()->GetMask(dwMask);
	   if(dwMask>0)
	   {
		     this->m_pPort->ComBreak(dwMask); 	     
	   }
	}

    EndThread:
	  	this->m_pPort->GetSerialPort()->Purge(PURGE_RXABORT | PURGE_RXCLEAR);  
        return ;   

}

void CReadComThread::ExecuteByManualConstRecvMode()
{
	DWORD dwMask=0;
	HANDLE WaitHandles[2]; //监听事件数组
	DWORD dwSignaledHandle;

	WaitHandles[0] = this->m_pPort->GetCloseHandle();
	WaitHandles[1] = this->m_BreakOverlapped.hEvent;

	this->m_pPort->GetSerialPort()->SetMask(EV_ERR | EV_RLSD | EV_RING ); 

	if(!SetBreakEvent(dwMask))
		goto EndThread;
		
    //设置comEvent
	for(;;)
	{
	   dwSignaledHandle=::WaitForMultipleObjects(2,WaitHandles,false,INFINITE);
       switch(dwSignaledHandle)
	   {
	      case WAIT_OBJECT_0:
              goto EndThread; 
			  break;

	      case WAIT_OBJECT_0+1:
			  if(!this->HandleBreakEvent(dwMask))
			    goto EndThread;
    		  if(!this->SetBreakEvent(dwMask))
	        	goto EndThread;
			  break;

		  default:
			  //goto EndThread;
			  break;
	   }
	   
  
	}

    EndThread:
	  	this->m_pPort->GetSerialPort()->Purge(PURGE_RXABORT | PURGE_RXCLEAR);  
	    ::CloseHandle(this->m_ReadOverlapped.hEvent);
	    ::CloseHandle(this->m_BreakOverlapped.hEvent);  
        return ;   

}
void CReadComThread::ExecuteByAutoBreakRecvMode()
{
   	DWORD dwMask=0;
	HANDLE WaitHandles[2]; //监听事件数组
	DWORD dwSignaledHandle;

	WaitHandles[0] = this->m_pPort->GetCloseHandle();
	WaitHandles[1] = this->m_BreakOverlapped.hEvent;

	this->m_pPort->GetSerialPort()->SetMask(EV_ERR | EV_RLSD | EV_RING | EV_RXCHAR); 

	if(!SetBreakEvent(dwMask))
		goto EndThread;
	//设置读事件
	if(!SetReadEvent(this->m_BreakOverlapped))
		goto EndThread;

    //设置comEvent
	for(;;)
	{
	   dwSignaledHandle=::WaitForMultipleObjects(2,WaitHandles,false,INFINITE);
       switch(dwSignaledHandle)
	   {
	      case WAIT_OBJECT_0:
              goto EndThread; 
			  break;

	      case WAIT_OBJECT_0+1:
              if((dwMask&EV_RXCHAR)==EV_RXCHAR)
			  {
                  if(!this->HandleReadEvent(this->m_BreakOverlapped))
					 goto EndThread;
                  if(!SetReadEvent(this->m_BreakOverlapped))
		             goto EndThread;
			  }
			  else
			  {
			      if(!this->HandleBreakEvent(dwMask))
			        	goto EndThread;
    			  if(!this->SetBreakEvent(dwMask))
	        		    goto EndThread;
			  }
			  break;

		  default:
			  //goto EndThread;
			  break;
	   }
	   
  
	}

    EndThread:
	  	this->m_pPort->GetSerialPort()->Purge(PURGE_RXABORT | PURGE_RXCLEAR);  
	    ::CloseHandle(this->m_ReadOverlapped.hEvent);
	    ::CloseHandle(this->m_BreakOverlapped.hEvent);  
        return ;   

}

DWORD WINAPI ThreadFunc(LPVOID  lpParam ) 
{ 
    CReadComThread* pThread =(CReadComThread*)lpParam;
	ASSERT(pThread);
	pThread->m_IsTerminated = false;
    pThread->Execute(); 
	pThread->m_IsTerminated = true;
	return 0;
} 

void CReadComThread::Create()
{
    m_hThread = CreateThread( 
        NULL,                        // no security attributes 
        0,                           // use default stack size  
        ThreadFunc,                  // thread function 
        this,                // argument to thread function 
        CREATE_SUSPENDED,           // use default creation flags 
        &dwThreadId);                // returns the thread identifier 
	::SetThreadPriority(m_hThread,THREAD_PRIORITY_HIGHEST); 
    
}

void CReadComThread::Terminate()
{
   char szMsg[80];
   if (m_hThread == NULL) 
   {
      wsprintf( szMsg, "CreateThread failed." ); 
	  ::MessageBox(NULL,szMsg,"ok",0);
   }
   else 
   {
      if(!this->IsTerminated())
	  {
	     Sleep(1000);
	  }
	  if(!this->IsTerminated())
	  {
         Sleep(1000);
         //::TerminateThread(m_hThread,0);
	  }
      CloseHandle( m_hThread );
   }
}

void CReadComThread::Resume()
{
   ResumeThread(this->m_hThread); 
}

void CReadComThread::BandSerialPort(CComPort* pPort)
{
	ASSERT(pPort);
	this->m_pPort = pPort;
	//创建异步读取事件
     
	if(this->m_pPort->IsOverlapped())
	{
	   this->m_ReadOverlapped.hEvent =::CreateEvent(NULL,false,false,NULL);	
	   ASSERT(this->m_ReadOverlapped.hEvent);  
       this->m_BreakOverlapped.hEvent = ::CreateEvent(NULL,false,false,NULL);
	   ASSERT(this->m_BreakOverlapped.hEvent); 
	}
	
}

DWORD CReadComThread::ReadInput(void* pBuf,DWORD Count,DWORD dwMilliseconds)
{
	DWORD dwRead=0;
	if(!this->m_pPort->GetSerialPort()->Read(pBuf,Count,this->m_ReadOverlapped,&dwRead))
	{
		try
		{
		if(WaitForSingleObject(this->m_ReadOverlapped.hEvent,dwMilliseconds)==WAIT_OBJECT_0)
		{
		    this->m_pPort->GetSerialPort()->GetOverlappedResult(this->m_ReadOverlapped,dwRead,false);
		}
		}
		catch(...)
		{
			return 0;
		}
	}

	return dwRead;   
   
}

}